package com.weishuang.monitor.leader.config.security;

import com.weishuang.monitor.leader.commons.jwt.JwtTokenUtil;
import com.weishuang.monitor.leader.config.client.ClientCodeAuthenticationSecurityConfig;
import com.weishuang.monitor.leader.config.client.JwtAuthenticationFilter;
import com.weishuang.monitor.leader.config.provider.CustomerAuthenticationProvider;
import com.weishuang.monitor.leader.config.security.handler.*;
import com.weishuang.monitor.leader.config.security.handler.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.sql.DataSource;

/**
 * spirng security 配置
 */
@Configuration
@EnableWebSecurity
public class CustomerSecurityConfigurer extends WebSecurityConfigurerAdapter {

//    @Autowired
//    private  jwtAuthenticationFilter;

    @Autowired
    private ClientCodeAuthenticationSecurityConfig clientCodeAuthenticationSecurityConfig;

    @Autowired
    private CustomerAuthenticationProvider authenticationProvider;

    @Autowired
    private CustomUserDetailsService userDetailsService;

    @Autowired
    private DataSource dataSource;

    @Autowired
    private CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler;

    @Autowired
    private CustomAuthenticationFailureHandler customAuthenticationFailureHandler;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        JwtAuthenticationFilter jwtAuthenticationFilter = new JwtAuthenticationFilter(authenticationManager());
        jwtAuthenticationFilter.setJwtTokenUtil(jwtTokenUtil);
        http.addFilter(jwtAuthenticationFilter);
        //客户端鉴权配置
        http.apply(clientCodeAuthenticationSecurityConfig);
        //鉴权相关配置
        http.authorizeRequests((authorize) -> {
            authorize.antMatchers("/login").permitAll();
            //客户端鉴权配置
            authorize.antMatchers("/api/authentication").permitAll();
            //所有客户端接口需要CLIENT角色
            authorize.antMatchers("/api/**").hasRole("CLIENT");
            authorize.antMatchers("/leader/**").hasRole("LEADER");
            authorize.anyRequest().authenticated();
        });
        //无权限处理配置
        http.exceptionHandling().accessDeniedHandler(new CustomAccessDeniedHandler());
        //未登录返回处理配置
        http.exceptionHandling().authenticationEntryPoint(new CustomAuthenticationEntryPoint());
        //登录相关配置
        http.formLogin()
            .successHandler(customAuthenticationSuccessHandler)
            .failureHandler(customAuthenticationFailureHandler)
            .permitAll()
            .and()
            .csrf().disable().cors();
        //记住我相关配置
        http.rememberMe().tokenRepository(persistentTokenRepository()).userDetailsService(userDetailsService).tokenValiditySeconds(60*60*24*15).rememberMeParameter("rememberMe");
        //退出相关配置
        http.logout().logoutSuccessHandler(new CustomeLogoutSuccessHandler()).permitAll();
    }

    /**
     * 记住的信息持久化到数据库
     * @return
     */
    @Bean
    public PersistentTokenRepository persistentTokenRepository() {
        JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
        jdbcTokenRepository.setDataSource(dataSource);
        return jdbcTokenRepository;
    }

    /**
     * 自定义认证逻辑
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(authenticationProvider);
    }

    /**
     * 密码加密
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

}
